// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// For official documentation of this package, see http://golang.org/pkg/os/
// Newly written bits are mostly undocumented except when it's necessary to point out
// features and limitations specific to the HelenOS operating system.
//
// Some code is taken from the official package sources, HelenOS specific bits are new.
package os

import "syscall"
import "errors"
import "time"

const (
	PathSeparator     = '/'
	PathListSeparator = ':'
)

var hosError = errors.New("Not implemented in HelenOS")

var Args []string

func Chdir(dir string) error {
	if e := syscall.Chdir(dir); e != nil {
		return &PathError{"chdir", dir, e}
	}
	return nil
}

func Chmod(name string, mode FileMode) error {
	return &PathError{"chmod", name, hosError}
}

func Chown(name string, uid, gid int) error {
	return &PathError{"chown", name, hosError}
}

func Chtimes(name string, atime time.Time, mtime time.Time) error {
	return &PathError{"chtimes", name, hosError}
}

func Exit(code int) {
	syscall.Exit(code)
}

func Getegid() int {
	return 0
}

func Geteuid() int {
	return 0
}

func Getgid() int {
	return 0
}

func Getgroups() ([]int, error) {
	return []int{0}, nil
}

func Getpagesize() int {
	return syscall.Getpagesize()
}

func Getpid() int {
	return int(syscall.TaskGetID())
}

func Getppid() int {
	// FIXME
	return -1
}

func Getuid() int {
	return 0
}

func Getwd() (pwd string, err error) {
	pwd = syscall.Getcwd()
	err = nil
	return
}

func Hostname() (name string, err error) {
	return "", hosError
}

func IsPathSeparator(c uint8) bool {
	return c == PathSeparator
}

func Lchown(name string, uid, gid int) error {
	return &PathError{"lchown", name, hosError}
}

func Link(oldname, newname string) error {
	return &LinkError{"link", oldname, newname, hosError}
}

func syscallMode(perm FileMode) syscall.ModeT {
	// Permissions are not implemented in HelenOS.
	return syscall.ModeT(0)
}

func Mkdir(name string, perm FileMode) error {
	if e := syscall.Mkdir(name, syscallMode(perm)); e != nil {
		return &PathError{"mkdir", name, e}
	}
	return nil
}

func Pipe() (r *File, w *File, err error) {
	return nil, nil, NewSyscallError("pipe", hosError);
}

func Readlink(name string) (string, error) {
	return "", &PathError{"readlink", name, hosError}
}

// Remove removes the named file or directory.
// If there is an error, it will be of type *PathError.
func Remove(name string) error {
	// System call interface forces us to know
	// whether name is a file or directory.
	// Try both: it is cheaper on average than
	// doing a Stat plus the right one.
	e := syscall.Unlink(name)
	if e == nil {
		return nil
	}
	e1 := syscall.Rmdir(name)
	if e1 == nil {
		return nil
	}

	// Both failed: figure out which error to return.
	// OS X and Linux differ on whether unlink(dir)
	// returns EISDIR, so can't use that.  However,
	// both agree that rmdir(file) returns ENOTDIR,
	// so we can use that to decide which error is real.
	// Rmdir might also return ENOTDIR if given a bad
	// file path, like /etc/passwd/foo, but in that case,
	// both errors will be ENOTDIR, so it's okay to
	// use the error from unlink.
	if e1 != syscall.ENOTDIR {
		e = e1
	}
	return &PathError{"remove", name, e}
}

func Rename(oldname, newname string) error {
	err := syscall.Rename(oldname, newname)
	if err == nil {
		return nil
	} else {
		return &PathError{"rename", oldname, err}
	}
}

func Stat(name string) (fi FileInfo, err error) {
	var stat syscall.StatT
	if err := syscall.Stat(name, &stat); err != nil {
		return nil, &PathError{"stat", name, err}
	}
	return &fileStat{name, stat}, nil
}

// As HelenOS currently doesn't support symlinks, this is the same as Stat.
func Lstat(name string) (fi FileInfo, err error) {
	return Stat(name)
}

func Symlink(oldname, newname string) error {
	return &LinkError{"symlink", oldname, newname, hosError}
}

func TempDir() string {
	// FIXME
	return "/tmp"
}

func Truncate(name string, size int64) error {
	fd, err := syscall.Open(name, syscall.O_WRONLY)
	if err != nil {
		return &PathError{"truncate", name, err}
	}
	
	err = syscall.FTruncate(fd, size)
	if err == nil {
		return nil
	} else {
		return &PathError{"truncate", name, err}
	}
}




